package com.ljx.funchat.user.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.ljx.funchat.chat.dao.RoomGroupMemberDao;
import com.ljx.funchat.chat.domain.entity.RoomFriend;
import com.ljx.funchat.chat.domain.enums.RoomStatusEnum;
import com.ljx.funchat.chat.domain.enums.RoomTypeEnum;
import com.ljx.funchat.chat.service.ChatService;
import com.ljx.funchat.chat.service.IRoomService;
import com.ljx.funchat.chat.service.adapter.MessageAdapter;
import com.ljx.funchat.common.constant.RedisKey;
import com.ljx.funchat.common.domain.vo.req.CursorPageBaseReq;
import com.ljx.funchat.common.domain.vo.resp.CursorPageBaseResp;
import com.ljx.funchat.common.event.UserApplyEvent;
import com.ljx.funchat.common.service.lock.LockService;
import com.ljx.funchat.common.utils.AssertUtil;
import com.ljx.funchat.user.dao.UserApplyDao;
import com.ljx.funchat.user.dao.UserFriendDao;
import com.ljx.funchat.user.domain.entity.UserApply;
import com.ljx.funchat.user.domain.entity.UserFriend;
import com.ljx.funchat.user.domain.enums.UserApplyStatusEnum;
import com.ljx.funchat.user.domain.enums.UserApplyTypeEnum;
import com.ljx.funchat.user.domain.vo.req.UserFriendApplyReq;
import com.ljx.funchat.user.domain.vo.req.UserFriendHandleReq;
import com.ljx.funchat.user.domain.vo.resp.UserApplyResp;
import com.ljx.funchat.user.service.IUserApplyService;
import com.ljx.funchat.user.service.IUserFriendService;
import com.ljx.funchat.user.service.adatper.UserApplyAdapter;
import com.ljx.funchat.user.service.adatper.UserFriendAdapter;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.ljx.funchat.common.constant.RedisKey.USER_APPLY_LOCK_EXPIRE;
import static com.ljx.funchat.common.constant.RedisKey.USER_APPROVE_LOCK_EXPIRE;

@Service
public class ApplyServiceImpl implements IUserApplyService {

    @Autowired
    private LockService lockService;

    @Autowired
    private UserApplyDao userApplyDao;

    @Autowired
    private RoomGroupMemberDao roomGroupMemberDao;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    private UserFriendDao userFriendDao;

    @Autowired
    private IRoomService roomService;

    @Autowired
    private ChatService chatService;

    @Override
    public void apply(Long uid, UserFriendApplyReq req) {
        Long targetId = req.getUid();
        Integer type = req.getType();
        lockService.executeWithLock(RedisKey.getKey(RedisKey.USER_APPLY_LOCK, uid), USER_APPLY_LOCK_EXPIRE, TimeUnit.SECONDS, () -> {
            // 检查申请
            checkApply(uid, targetId, type);
            // 如果对方已经提交申请则直接同意
            UserApply targetApply = userApplyDao.getByUidAndTargetId(targetId, uid, type);
            if (Objects.nonNull(targetApply)) {
                ((IUserApplyService) AopContext.currentProxy()).approveApply(uid, targetApply.getId());
            }
            // 保存申请
            UserApply insert = UserApplyAdapter.buildApplySave(uid, req);
            userApplyDao.save(insert);
            // 推送好友申请
            applicationEventPublisher.publishEvent(new UserApplyEvent(this, insert));
        });
    }

    /**
     * 检查申请信息
     * @param uid
     * @param targetId
     * @param type
     */
    private void checkApply(Long uid, Long targetId, Integer type) {
        AssertUtil.notEqual(targetId, uid, "不能添加自己为好友哦");
        UserApply apply = userApplyDao.getByUidAndTargetId(uid, targetId, type);
        if (type.equals(UserApplyTypeEnum.FRIEND.getStatus())){
            boolean isFriend = userFriendDao.countIsFriend(uid, targetId);
            AssertUtil.isFalse(isFriend, "已经是好友关系了");
        } else {
            boolean isJoin = roomGroupMemberDao.countIsJoin(uid, targetId);
            AssertUtil.isFalse(isJoin, "已经加入该群聊了");
        }
        if (Objects.nonNull(apply)){
            // 已经有提交记录
            AssertUtil.notEqual(apply.getStatus(), UserApplyStatusEnum.WAIT, "请勿重复提交申请");
            // 删除已经提交的记录【之前是好友可能后面删除了】
            userApplyDao.removeById(apply.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleApply(Long uid, UserFriendHandleReq req) {
        // 同意申请
        userApplyDao.updateByApplyId(uid, req);
        // 同意就需要新增会话
        if (req.getStatus().equals(UserApplyStatusEnum.AGREE.getStatus())) {
            ((IUserApplyService) AopContext.currentProxy()).approveApply(uid, req.getApplyId());
        }
    }

    @Override
    public CursorPageBaseResp<UserApplyResp> applyPage(Long uid, CursorPageBaseReq req) {
        CursorPageBaseResp<UserApply> applyPageResp = userApplyDao.getApplyPage(uid, req);
        List<UserApplyResp> respList = UserApplyAdapter.buildApplyResp(applyPageResp.getList());
        return CursorPageBaseResp.init(applyPageResp, respList);
    }

    @Override
    public void approveApply(Long uid, Long applyId) {
        lockService.executeWithLock(RedisKey.getKey(RedisKey.USER_APPROVE_LOCK, uid), USER_APPROVE_LOCK_EXPIRE, TimeUnit.SECONDS, () -> {
            UserApply userApply = userApplyDao.getById(applyId);
            AssertUtil.isNotEmpty(userApply, "不存在申请记录");
            AssertUtil.notEqual(userApply.getStatus(), UserApplyStatusEnum.WAIT, "该申请已经处理过了");
            if (userApply.getType().equals(UserApplyTypeEnum.FRIEND.getStatus())) {
                AssertUtil.equal(userApply.getTargetId(), uid, "不存在申请记录");
                AssertUtil.equal(userApply.getStatus(), UserApplyStatusEnum.AGREE.getStatus(), "已同意好友申请");
                // 新增好友关系
                createFriend(userApply.getUid(), userApply.getTargetId());
                // 创建聊天房间
                RoomFriend roomFriend = roomService.createFriendRoom(Arrays.asList(userApply.getTargetId(), userApply.getUid()), RoomTypeEnum.FRIEND.getType());
                // 接收者发送消息【我们已经是好友了，开始聊天吧】
                chatService.sendMsg(uid, MessageAdapter.buildAgreeMsg(roomFriend.getRoomId(), uid));
            } else if (userApply.getType().equals(UserApplyTypeEnum.GROUP.getStatus())) {


            }
        });
    }

    private void createFriend(Long uid, Long targetId) {
        // 查询是否曾经是好友，存在就直接恢复
        List<UserFriend> userFriendList = userFriendDao.getFriendByIds(uid, targetId);
        if (CollectionUtil.isNotEmpty(userFriendList)) {
            List<UserFriend> userFriends = userFriendList.stream().map(item -> {
                item.setDeleteStatus(RoomStatusEnum.NORMAL.getStatus());
                return item;
            }).collect(Collectors.toList());
            userFriendDao.updateBatchById(userFriends);
            return;
        }

        UserFriend userFriend1 = UserFriendAdapter.buildUserFriend(uid, targetId);
        UserFriend userFriend2 = UserFriendAdapter.buildUserFriend(targetId, uid);
        userFriendDao.saveBatch(Arrays.asList(userFriend1, userFriend2));
    }

    @Override
    public void deleteApply(Long applyId) {
        userApplyDao.removeById(applyId);
    }
}
